package com.jctrip.hotel.source.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.jctrip.hotel.common.enums.SourceEnum;
import com.jctrip.hotel.common.util.DateUtil;
import com.jctrip.hotel.domain.dao.*;
import com.jctrip.hotel.domain.entity.*;
import com.jctrip.hotel.source.client.HworldCallBackClient;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.jctrip.hotel.common.constant.RedisKeyConstant;
import com.jctrip.hotel.common.constant.XxlJobNameConstant;
import com.jctrip.hotel.common.context.BeanContext;
import com.jctrip.hotel.common.route2source.model.param.Route2SourceQueryOrderParam;
import com.jctrip.hotel.common.route2source.model.result.Route2SourceQueryOrderResult;
import com.jctrip.hotel.common.route2source.service.Route2SourceOrderService;
import com.jctrip.hotel.common.threadpool.XxlJobThreadPool;
import com.jctrip.hotel.common.util.RedisUtil;
import com.jctrip.hotel.source.service.HotelCommonTaskService;

import lombok.extern.slf4j.Slf4j;

/**
 * @Author henry
 * @Date 2023/7/12 19:22
 * @Description
 */
@Service
@Slf4j
public class HotelCommonTaskServiceImpl implements HotelCommonTaskService {
    private static final long PUSH_EXPIRY = 1 * 60;
    private static final XxlJobThreadPool syncHotelOrderTaskPool =
            new XxlJobThreadPool(XxlJobNameConstant.SYNC_HT_SOURCE_ORDER_UPDATE_TASK_POP);
    @Resource
    private HtOrderSourceRecordDao htOrderSourceRecordDao;
    @Resource
    private HtSourceInfoDao htSourceInfoDao;
    @Autowired
    private Route2SourceOrderService route2SourceOrderService;
    @Resource
    private HtOrderRouteRecordDao htOrderRouteRecordDao;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private MgOrderLogDao mgOrderLogDao;
    @Resource
    private HtOrderErrorLogDao htOrderErrorLogDao;
    @Autowired
    private HworldCallBackClient hworldCallBackClient;

    @Override
    public void syncHotelOrderTask(String bookId) {
        try {
            HtOrderSourceRecord htOrderSourceRecord = htOrderSourceRecordDao.selectOne(
                    new LambdaQueryWrapper<HtOrderSourceRecord>().eq(HtOrderSourceRecord::getBookId, bookId));
            if (htOrderSourceRecord == null) {
                return;
            }

            HtSourceInfo htSourceInfo =
                    htSourceInfoDao.selectOne(new LambdaQueryWrapper<HtSourceInfo>().eq(HtSourceInfo::getSourceId,
                            htOrderSourceRecord.getSourceId()));
            if (htSourceInfo == null) {
                return;
            }
            // 获取订单信息
            Route2SourceQueryOrderParam queryOrderParam = Route2SourceQueryOrderParam.builder()
                    .sourceCode(htOrderSourceRecord.getSourceCode())
                    .sourceAppId(htSourceInfo.getSourceAppId())
                    .sourceSecret(htSourceInfo.getSourceSecret())
                    .bookId(htOrderSourceRecord.getBookId())
                    .sourceOrderId(htOrderSourceRecord.getSourceOrderId())
                    .hotelId(htOrderSourceRecord.getHotelId())
                    .extra(htSourceInfo.getExtra())
                    .build();
            Route2SourceQueryOrderResult queryOrderResult = route2SourceOrderService.queryOrder(queryOrderParam);
            // 查询到订单是已确认且当前状态是待确认时 调用一下飞猪的发货
            if (htOrderSourceRecord.getSourceCode().equals(SourceEnum.ELONGDOM.getCode())
                    && queryOrderResult.getSourceOrderStatus() == 1
                    && (System.currentTimeMillis() - htOrderSourceRecord.getCreateTime().getTime()) / 60000 <= 15) {
                hworldCallBackClient.sendGoods(bookId);
            }
            // 更新订单状态
            htOrderSourceRecordDao.update(null,
                    new LambdaUpdateWrapper<HtOrderSourceRecord>().set(HtOrderSourceRecord::getSourceOrderStatus,
                            queryOrderResult.getSourceOrderStatus())
                            .set(!htOrderSourceRecord.getSourceOrderStatus()
                                            .equals(queryOrderResult.getSourceOrderStatus()),
                                    HtOrderSourceRecord::getOrderModifyTime, new Date())
                            .eq(HtOrderSourceRecord::getBookId, bookId));
            // 同步到已入住的状态的时候 加入日志表
            if (queryOrderResult.getSourceOrderStatus() == 4) {
                insertOrderLog(htOrderSourceRecord);
            }

        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }


    @Override
    public void syncHotelOrderListTaskFastPush() {

        try {
            // 0：待确认 1：预订成功 2：已取消 3：预订未到 4：已入住 5：已完成 6：确认失败
            // 未完成订单 0 1 3 4
            LambdaQueryWrapper<HtOrderSourceRecord> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(HtOrderSourceRecord::getSourceOrderStatus, Arrays.asList(0, 1, 3, 4));
            // 离店日期在一周前
            queryWrapper.ge(HtOrderSourceRecord::getDepartDate, DateUtil.beginOfDay(DateUtils.addDays(new Date(), -7)));
            List<HtOrderSourceRecord> hotelSyncOrderList = htOrderSourceRecordDao.selectList(queryWrapper);
            if (CollectionUtils.isNotEmpty(hotelSyncOrderList)
                    && redisUtil.lGetListSize(RedisKeyConstant.HOTEL_ORDER_LIST) <= 0) {
                redisUtil.leftPushAll(RedisKeyConstant.HOTEL_ORDER_LIST,
                        hotelSyncOrderList.stream().map(HtOrderSourceRecord::getBookId).collect(
                                Collectors.toList()));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

    }

    @Override
    public void syncHotelOrderListTaskFastPop() {
        syncHotelOrderTaskPool.execute(SyncHotelOrderTaskThread::new);
    }

    @Override
    public void insertOrderErrorLog(String bookId, String request, String response) {
        HtOrderErrorLog htOrderErrorLog = new HtOrderErrorLog();
        htOrderErrorLog.setBookId(bookId);
        htOrderErrorLog.setRequestBody(request);
        htOrderErrorLog.setResponseBody(response);
        htOrderErrorLogDao.insert(htOrderErrorLog);
    }

    private void insertOrderLog(HtOrderSourceRecord htOrderSourceRecord) {
        List<MgOrderLog> orderLogs = Optional.ofNullable(mgOrderLogDao.selectList(
                new LambdaQueryWrapper<MgOrderLog>()
                        .eq(MgOrderLog::getOrderId, htOrderSourceRecord.getOrderId())))
                .orElse(new ArrayList<>());
        MgOrderLog mgOrderLog = orderLogs.stream().filter(e -> e.getInfo().endsWith("入住")).findFirst().orElse(null);
        if (Objects.nonNull(mgOrderLog)) {
            return;
        }

        mgOrderLog = new MgOrderLog();
        List<HtOrderRouteRecord> htOrderRouteRecords = Optional.ofNullable(htOrderRouteRecordDao.selectList(new LambdaQueryWrapper<HtOrderRouteRecord>()
                .eq(HtOrderRouteRecord::getOrderId, htOrderSourceRecord.getOrderId()))).orElse(new ArrayList<>());
        mgOrderLog.setRouteId(CollectionUtils.isEmpty(htOrderRouteRecords) ? htOrderSourceRecord.getSourceCode() : htOrderRouteRecords.get(0).getRouteId());
        mgOrderLog.setOrderId(htOrderSourceRecord.getOrderId());
        mgOrderLog.setInfo(String.format("%s订单入住", htOrderSourceRecord.getOrderId()));
        mgOrderLog.setOperator("System");
        mgOrderLogDao.insert(mgOrderLog);
    }

    /**
     * pop任务子线程
     */
    @Slf4j
    public static class SyncHotelOrderTaskThread implements Runnable {

        public SyncHotelOrderTaskThread() {
        }

        @Override
        public void run() {
            RedisUtil redisUtil = BeanContext.getApplicationContext().getBean(RedisUtil.class);
            HotelCommonTaskService hotelCommonTaskService =
                    BeanContext.getApplicationContext().getBean(HotelCommonTaskService.class);
            try {
                while (redisUtil.lGetListSize(RedisKeyConstant.HOTEL_ORDER_LIST) > 0) {
                    String bookId = (String) redisUtil.rightPop(RedisKeyConstant.HOTEL_ORDER_LIST);
                    if (StringUtils.isBlank(bookId)) {
                        continue;
                    }
                    hotelCommonTaskService.syncHotelOrderTask(bookId);
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
    }
}
